//
//  NSObject+BPSwizzle.m
//  BPCrashDemo
//
//  Created by SiYugui on 2019/12/18.
//  Copyright © 2019年 SiYugui. All rights reserved.
//

#import "NSObject+BPSwizzle.h"

@implementation NSObject (BPSwizzle)

#pragma mark - 实例方法

+(void)exchangeClassMethod:(SEL)original_meathod method2:(SEL)replace_meathod{
    Class class = [self class];
    [self exchangeClassMethod:class method1:original_meathod method2:replace_meathod];
}

+(void)exchangeClassMethod:(Class)obj_class method1:(SEL)m1 method2:(SEL)m2{
    
    // Method中包含IMP函数指针，通过替换IMP，使SEL调用不同函数实现
    Method originalMeathod = class_getClassMethod(obj_class, m1);
    Method replaceMeathod = class_getClassMethod(obj_class, m2);
    Class meta_class = objc_getMetaClass(NSStringFromClass(obj_class).UTF8String);
    
    // class_addMethod:如果发现方法已经存在，会失败返回，也可以用来做检查用,我们这里是为了避免源方法没有实现的情况;如果方法没有存在,我们则先尝试添加被替换的方法的实现
    BOOL didAddMethod = class_addMethod(meta_class,
                                        m1,
                                        method_getImplementation(replaceMeathod),
                                        method_getTypeEncoding(replaceMeathod));
    if (didAddMethod) {
        // 原方法未实现，则替换原方法防止crash
        class_replaceMethod(meta_class,
                            m2,
                            method_getImplementation(originalMeathod),
                            method_getTypeEncoding(originalMeathod));
    }else {
        // 添加失败：说明源方法已经有实现，直接将两个方法的实现交换即
        method_exchangeImplementations(originalMeathod, replaceMeathod);
    }
}

#pragma mark - 类方法

+(void)exchangeInstanceMethod:(Class)obj_class method1:(SEL)m1 method2:(SEL)m2{
    
    Method originalMeathod = class_getInstanceMethod(obj_class, m1);
    Method replaceMeathod = class_getInstanceMethod(obj_class, m2);
    
    // class_addMethod:如果发现方法已经存在，会失败返回，也可以用来做检查用,我们这里是为了避免源方法没有实现的情况;如果方法没有存在,我们则先尝试添加被替换的方法的实现
    BOOL didAddMethod = class_addMethod(obj_class,
                                        m1,
                                        method_getImplementation(replaceMeathod),
                                        method_getTypeEncoding(replaceMeathod));
    if (didAddMethod) {
        // 原方法未实现，则替换原方法防止crash
        class_replaceMethod(obj_class,
                            m2,
                            method_getImplementation(originalMeathod),
                            method_getTypeEncoding(originalMeathod));
    }else {
        // 添加失败：说明源方法已经有实现，直接将两个方法的实现交换即
        method_exchangeImplementations(originalMeathod, replaceMeathod);
    }
}

+(void)exchangeInstanceMethod:(SEL)original_meathod method2:(SEL)replace_meathod{
    Class class = [self class];
    [self exchangeInstanceMethod:class method1:original_meathod method2:replace_meathod];
}

@end
